package com.cc.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cc.constant.BusinessStatusConstant;
import com.cc.entity.FileEntity;
import com.cc.mapper.FileMapper;
import com.cc.service.FileService;
import com.cc.service.SliceUploadHelper;
import com.cc.util.*;
import com.github.tobato.fastdfs.domain.fdfs.MetaData;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.*;

import static com.cc.constant.BusinessStatusConstant.BUSINESS_EXCEPTION;

@Slf4j
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, FileEntity> implements FileService {

    @Autowired
    private SliceUploadHelper sliceUploadHelper;

    @Autowired
    private FastDFSUtil fastDFSUtil;

    @Autowired
    private FileMapper fileMapper;

    @Override
    public String uploadFileBySlices(MultipartFile[] files, String fileMd5) throws Exception {
        FileEntity fileEntity = findFileEntityByMd5(fileMd5);
        if (fileEntity != null) {
            return fileEntity.getUrl();
        }
        String resultPath = "";
        int totalSliceNo = files.length;
        // 创建一个固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(1);
        CompletionService<String> completionService = new ExecutorCompletionService<>(executor);
        for (int sliceNo = 0; sliceNo < totalSliceNo; sliceNo++) {
            try {
                MultipartFile file = files[sliceNo];
                int finalSliceNo = sliceNo + 1;
                completionService.submit(() -> {
                    try {
                        return sliceUploadHelper.uploadFileBySlices(file, finalSliceNo, totalSliceNo, fileMd5);
                    } catch (Exception e) {
                        throw new ConditionException(BusinessStatusConstant.BUSINESS_EXCEPTION, "Error uploading file slice: " + e.getMessage());
                    }
                });
            }catch (Exception e) {
                throw new ConditionException(BusinessStatusConstant.BUSINESS_EXCEPTION, e.getMessage());
            }
        }
        for (int i = 1; i <= totalSliceNo; i++) {
            try {
                resultPath = completionService.take().get();
                log.info("FileServiceImpl 第 " + i + " 次 获取任务完成结果 ==================== > [{}]",resultPath);
            } catch (ExecutionException | InterruptedException e) {
                throw new ConditionException(BusinessStatusConstant.BUSINESS_EXCEPTION, "Error uploading file slices: " + e.getMessage());
            }
        }
        // 关闭线程池
        executor.shutdown();
        if(!resultPath.equals("")&&!resultPath.equals("")){
            String fileType = FileUtil.getFileType(files[0]);
            saveFileToDB(fileMd5, fileType, resultPath);
        }
        return resultPath;
    }

    @Override
    public String uploadFileBySlices(MultipartFile file, Integer sliceNo, Integer totalSliceNo, String fileMd5) throws Exception {
        FileEntity fileEntity = findFileEntityByMd5(fileMd5);
        if (fileEntity != null) {
            return fileEntity.getUrl();
        }
        String resultPath = sliceUploadHelper.uploadFileBySlices(file, sliceNo, totalSliceNo, fileMd5);
        if(!resultPath.equals("")){
            String fileType = FileUtil.getFileType(file);
            saveFileToDB(fileMd5, fileType, resultPath);
        }
        return resultPath;
    }


    @Override
    public String convertMultiFileBySlices(MultipartFile multipartFile) throws Exception {
        String fileMd5 = MD5Util.getInputStreamMD5Str(multipartFile.getInputStream());
        FileEntity fileEntity = findFileEntityByMd5(fileMd5);
        if (fileEntity != null) {
            return fileEntity.getUrl();
        }
        String resultPath = sliceUploadHelper.convertMultiFileBySlices(multipartFile, fileMd5);
        String fileType = FileUtil.getFileType(multipartFile);
        saveFileToDB(fileMd5, fileType, resultPath);
        return resultPath;
    }

    @Override
    public String simpUploadFile(MultipartFile file) throws Exception {
        Set<MetaData> metaData = new HashSet<>();
        return fastDFSUtil.uploadFile(file, metaData);
    }

    @Override
    public void deleteFilePath(String filePath) throws Exception {
        fastDFSUtil.deleteFile(filePath);
    }

    private FileEntity findFileEntityByMd5(String fileMd5) {
        QueryWrapper<FileEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("md5", fileMd5);
        return fileMapper.selectOne(wrapper);
    }

    private void saveFileToDB(String fileMd5, String fileType, String resultPath) {
        FileEntity fileDB = new FileEntity();
        fileDB.setMd5(fileMd5);
        fileDB.setType(fileType);
        fileDB.setUrl(resultPath);
        if(!this.save(fileDB)){
            throw new ConditionException(BUSINESS_EXCEPTION, "上传失败");
        }
    }

}
